package bsts.controller;

import java.util.HashMap;
import java.util.ArrayList;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;


import bsts.model.*;

public class IOController {
	
	private String fileName;
	private String fileDirectory;
	private String fileConfig;
	private HashMap<String,String> datafiles;
	
	public IOController(){
		this.datafiles = new HashMap<String,String>();
		this.fileConfig = "";
		this.fileName = "";
		this.fileDirectory = "";
		
		this.setConfiguration("config.ini");
		
		try{
			this.ReadConfiguration();	
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
	}
	
	private void WriteToFile(Object obj, String fileName)throws IOException{
		File f = new File(fileName);
		FileOutputStream fos = new FileOutputStream(f);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		
		oos.writeObject(obj);
		
		oos.close();
		fos.close();
		
	}
	
	private void WriteToFile(String fileContents, String fileName)throws IOException{
		File f = new File(fileName);
		FileWriter fw = new FileWriter(f);
		PrintWriter pw = new PrintWriter(fw);
		
		pw.write(fileContents);
		
		pw.close();
		fw.close();
	}
	
	private Object ReadFromFile(String fileName)throws IOException,ClassNotFoundException{
		Object o;
		
		FileInputStream fis = new FileInputStream(fileName);
		ObjectInputStream ois = new ObjectInputStream(fis);
		
		o = ois.readObject();
		
		ois.close();
		fis.close();
		
		return o;
	}
	
	private String ReadFromFile(String directory,String filename)throws IOException{
		String s = "";
		StringBuffer filecontents = new StringBuffer();
		
		FileReader fr = new FileReader(directory + "\\" + filename);
		BufferedReader br = new BufferedReader(fr);
				
		while((s = br.readLine()) != null){
			filecontents.append(s);
			filecontents.append("\n");
		}
		
		return filecontents.toString();
	}
	

	
	private String getDataDirectory(){
		String fileDirectory = "";
		
		fileDirectory = new File("").getAbsolutePath();
		fileDirectory = fileDirectory + "\\data\\";
		
		return fileDirectory;
	}
	
	//-start---------Bills text files----------------//
	public boolean WriteBill(String acctNo, String billContents, String billFileName){
		
		//Sets the filename
		this.fileName = billFileName + ".txt";
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		//Add the required path to the Bill subfolder
		this.fileDirectory = this.fileDirectory + "bills\\" + acctNo;
		
		if (!(new File(this.fileDirectory).exists())){
			// org
			//new File(this.fileDirectory).mkdir();
			// modified by cw
			new File(this.fileDirectory).mkdirs();
		}
		
		try{
			this.WriteToFile(billContents, this.fileDirectory + "\\" +this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public String ReadBill(String acctNo, String billFileName){
		String billText = "";
		
        this.fileName = billFileName + ".txt";
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		//Add the required path to the Bill subfolder
		this.fileDirectory = this.fileDirectory + "bills\\" + acctNo + "\\";
		
		try {
			billText = this.ReadFromFile(this.fileDirectory, this.fileName);
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
		
		return billText;
	}
	//-end-----------Bills text files----------------//
	
	//-start---------Subscription.dat----------------//
	public boolean UpdateSubscription(ArrayList<Subscription> subscriptions){
		
		this.fileName = datafiles.get("Subscription_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(subscriptions, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public ArrayList<Subscription> RetrieveSubscriptions(){
		ArrayList<Subscription> subscriptions = new ArrayList<Subscription>();
		
		this.fileName = datafiles.get("Users_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			subscriptions = (ArrayList<Subscription>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return subscriptions;
	}
	//-end---------Subscription.dat----------------//
		
	//-start---------Users.dat----------------//
	public boolean UpdateUsers(HashMap<String,User> users){
		
		this.fileName = datafiles.get("Users_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(users, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public HashMap<String,User> RetrieveUsers(){
		HashMap<String,User> users = new HashMap<String,User>();
		
		this.fileName = datafiles.get("Users_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			users = (HashMap<String,User>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return users;
	}
	//-end---------Users.dat----------------//
	
	//-start---------Customer.dat----------------//
	public boolean UpdateCustomers(HashMap<String,Customer> customers){
		
		this.fileName = datafiles.get("Customer_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(customers, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public HashMap<String,Customer> RetrieveCustomers(){
		HashMap<String,Customer> customers = new HashMap<String,Customer>();
		
		this.fileName = datafiles.get("Customer_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			customers = (HashMap<String,Customer>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return customers;
	}
	//-end---------Customer.dat----------------//
	
	//-start-------Bill.dat--------------------//
	public boolean UpdateBills(ArrayList<Bill> bills){
		
		this.fileName = datafiles.get("Bill_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(bills, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public ArrayList<Bill> RetrieveBills(){
		ArrayList<Bill> bills = new ArrayList<Bill>();
		
		this.fileName = datafiles.get("Bill_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			bills = (ArrayList<Bill>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return bills;
	}
	//-end---------Bill.dat-------------------//
	
	//-start-------Payment.dat-----------------//
	public boolean UpdatePayments(ArrayList<Payment> payments){
		
		this.fileName = datafiles.get("Payment_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			System.out.println("Start writing into payment file Directory = "+this.fileDirectory+" File name:"+this.fileName);
			this.WriteToFile(payments, this.fileDirectory + this.fileName);			
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public ArrayList<Payment> RetrievePayments(){
		ArrayList<Payment> payments = new ArrayList<Payment>();
		
		this.fileName = datafiles.get("Payment_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			payments = (ArrayList<Payment>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return payments;
	}
	
	//-end---------Payment.dat-----------------//
	
	//-start-------Complaint.dat-----------------//
	public boolean UpdateComplaints(ArrayList<Complaint> complaints){
		
		this.fileName = datafiles.get("Complaint_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(complaints, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;

	}
	
	public ArrayList<Complaint> RetrieveComplaints(){
		ArrayList<Complaint> complaints = new ArrayList<Complaint>();
		
		this.fileName = datafiles.get("Complaint_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			complaints = (ArrayList<Complaint>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return complaints;
	}
	//-end---------Complaint.dat-----------------//

	//-start-------Transaction.dat---------------//
	public boolean UpdateTransactions(ArrayList<Transaction> transactions){
		
		this.fileName = datafiles.get("Transaction_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(transactions, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public ArrayList<Transaction> RetrieveTransactions(){
		ArrayList<Transaction> transactions = new ArrayList<Transaction>();
		
		this.fileName = datafiles.get("Transaction_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			transactions = (ArrayList<Transaction>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return transactions;
	}
	//-end---------Transaction.dat---------------//

	//-start-------Plan-----------------//
	public boolean UpdatePlans(ArrayList<Plan> plans){
		
		this.fileName = datafiles.get("Plan_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(plans, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;

	}
	
	public ArrayList<Plan> RetrievePlans(){
		ArrayList<Plan> plans = new ArrayList<Plan>();
		
		this.fileName = datafiles.get("Plan_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			plans = (ArrayList<Plan>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return plans;
	}
	//-end---------Plan-----------------//
	
	//-start-------Feature-----------------//
	public boolean UpdateFeatures(ArrayList<Feature> features){
		
		this.fileName = datafiles.get("Feature_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			this.WriteToFile(features, this.fileDirectory + this.fileName);
		}catch (IOException e){
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;

	}
	
	public ArrayList<Feature> RetrieveFeatures(){
		ArrayList<Feature> features = new ArrayList<Feature>();
		
		this.fileName = datafiles.get("Feature_data");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try{
			features = (ArrayList<Feature>)this.ReadFromFile(fileDirectory+fileName);	
		}catch (ClassNotFoundException e){
			System.out.println(e.getMessage());
			
		}catch (IOException e){
			System.out.println(e.getMessage());
		}
		
		return features;
	}
	
	//-end---------Feature-----------------//
	
	//Done by Karpal
	private void setConfiguration(String fileConfig){
		this.fileConfig = fileConfig;
	}
	
	public String getConfiguration(){
		return(this.fileConfig);
	}
	
	//Done by Karpal
	//To read the config.ini file.
	public void ReadConfiguration()throws IOException{
		String FileConfigContents = "";
		String[] FileConfigContent;
		CharSequence fileComment = "'";
		
		File f = new File(this.fileConfig);
		FileReader fr = new FileReader(f);
		BufferedReader br = new BufferedReader(fr);
		
		while ((FileConfigContents=br.readLine())!= null)
		{
			if (!FileConfigContents.contains(fileComment)){
				FileConfigContent = FileConfigContents.split("=");
				datafiles.put(FileConfigContent[0], FileConfigContent[1]);
			}
		}
		
		br.close();
		fr.close();
	}
	//---------------------------------------------//
	
	
	// added by cw
	public boolean UpdateAccountID(int accountCount) {
		this.fileName = datafiles.get("Account_ID");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
				
		try {
			this.WriteToFile(String.valueOf(accountCount), this.fileDirectory + this.fileName);
		} catch (IOException e) {
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public int RetrieveAccountID() {		
		this.fileName = datafiles.get("Account_ID");
		int accountCount = 0;
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try {
			accountCount = Integer.parseInt(this.ReadFromFile(this.fileDirectory, this.fileName).trim());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		
		return accountCount;
	}
	
	public boolean UpdateSubscriptionID(long subID) {
		this.fileName = datafiles.get("Subscription_ID");
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
				
		try {
			this.WriteToFile(String.valueOf(subID), this.fileDirectory + this.fileName);
		} catch (IOException e) {
			System.out.println(e.getMessage());
			return false;
		}
		
		return true;
	}
	
	public long RetrieveSubscriptionID() {		
		this.fileName = datafiles.get("Subscription_ID");
		long subID = 0;
		
		//Gets the path to the working directory to the data directory
		this.fileDirectory = this.getDataDirectory();
		
		try {
			subID = Long.parseLong(this.ReadFromFile(this.fileDirectory, this.fileName).trim());
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		
		return subID;
	}
	// end of added by cw
	
}
